package com.ccb.sc.order.service.impl;

import cn.hutool.core.lang.UUID;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Lists;
import com.ccb.sc.constant.OrderConstant;
import com.ccb.sc.groupon.service.AppGrouponService;
import com.ccb.sc.groupon.vo.GrouponCreateVo;
import com.ccb.sc.member.service.AppMemberService;
import com.ccb.sc.member.service.ReceiverService;
import com.ccb.sc.member.vo.ReceiverVo;
import com.ccb.sc.order.controller.query.AppOrderCommonQueryParam;
import com.ccb.sc.order.mapper.AppOrderMapper;
import com.ccb.sc.order.service.IAppOrderService;
import com.ccb.sc.order.service.ShoppingCartService;
import com.ccb.sc.order.vo.*;
import com.ccb.sc.order.vo.OrderCreateVo;
//psl import com.ccb.sc.common.bind.exception.BizException;
import com.ccb.sc.common.bind.page.PageParams;
import com.ccb.sc.common.bind.page.PageVo;
import com.ccb.sc.common.code.BizCodeFace;
import com.ccb.sc.common.code.ErrorCode;
import com.ccb.sc.common.modules.common.service.IDeliveryService;
import com.ccb.sc.common.modules.common.service.IRedisService;
import com.ccb.sc.common.modules.common.vo.QueryTrackResp;
import com.ccb.sc.common.modules.goods.entity.Goods;
import com.ccb.sc.common.modules.goods.entity.GoodsComment;
import com.ccb.sc.common.modules.goods.entity.GoodsSpecs;
import com.ccb.sc.common.modules.goods.enums.GoodsType;
import com.ccb.sc.common.modules.goods.mapper.GoodsCommentMapper;
import com.ccb.sc.common.modules.goods.mapper.GoodsMapper;
import com.ccb.sc.common.modules.goods.mapper.GoodsSpecsMapper;
import com.ccb.sc.common.modules.goods.vo.GoodsCommentCreateVo;
import com.ccb.sc.common.modules.groupon.entity.GrouponLog;
import com.ccb.sc.common.modules.member.entity.Member;
import com.ccb.sc.common.modules.member.entity.Receiver;
import com.ccb.sc.common.modules.member.enums.MemberPointsLogType;
import com.ccb.sc.common.modules.member.enums.MemberStatus;
import com.ccb.sc.common.modules.member.service.MemberPointsService;
import com.ccb.sc.common.modules.message.service.MessageService;
import com.ccb.sc.common.modules.order.convert.OrderConvert;
import com.ccb.sc.common.modules.order.entity.*;
import com.ccb.sc.common.modules.order.enums.CommentStatus;
import com.ccb.sc.common.modules.order.enums.DeliverStatus;
import com.ccb.sc.common.modules.order.enums.OrderLogType;
import com.ccb.sc.common.modules.order.enums.OrderStatus;
import com.ccb.sc.common.modules.order.mapper.OrderLogMapper;
import com.ccb.sc.common.modules.order.mapper.OrderReturnMapper;
import com.ccb.sc.common.modules.order.service.IOrderCommentService;
import com.ccb.sc.common.modules.order.service.IOrderItemService;
import com.ccb.sc.common.modules.order.vo.*;
import com.ccb.sc.common.modules.payment.entity.Payment;
import com.ccb.sc.common.modules.payment.enums.OrderType;
import com.ccb.sc.common.modules.payment.enums.PaymentStatus;
import com.ccb.sc.common.modules.setting.service.ISettingsService;
import com.ccb.sc.common.modules.setting.vo.OrderSettingsVo;
import com.ccb.sc.common.modules.shopkeeper.entity.Shopkeeper;
import com.ccb.sc.common.modules.shopkeeper.entity.ShoppingCart;
import com.ccb.sc.common.modules.shopkeeper.enums.ShopkeeperPointsLogType;
import com.ccb.sc.common.modules.shopkeeper.service.ShopkeeperPointsLogService;
import com.ccb.sc.common.modules.shopkeeper.service.ShopkeeperService;
import com.ccb.sc.common.util.IpUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 订单表 服务实现类
 * </p>
 *
 * @author ken
 * @since 2020-09-25
 */
@Service
public class AppOrderServiceImpl extends ServiceImpl<AppOrderMapper, Order> implements IAppOrderService {

    private final Logger logger = LoggerFactory.getLogger(IAppOrderService.class);

    private ReceiverService receiverService;
    private IRedisService redisService;
    private ISettingsService settingsService;
    private GoodsSpecsMapper goodsSpecsMapper;
    private GoodsMapper goodsMapper;
    private IOrderItemService orderItemService;
    private AppMemberService memberService;
    private OrderLogMapper  orderLogMapper;
    private IOrderCommentService orderCommentService;
    private GoodsCommentMapper goodsCommentMapper;
    private IDeliveryService deliveryService;
    private OrderReturnMapper orderReturnMapper;
    private MemberPointsService memberPointsService;
    private MessageService messageService;
    private ShoppingCartService shoppingCartService;
    private ShopkeeperService shopkeeperService;
    private ShopkeeperPointsLogService shopkeeperPointsLogService;
    private AppGrouponService grouponService;


    @Override
    public OrderPreviewVo preview(Long memberId) {
        Member member = this.memberService.getById(memberId);

        OrderPreviewVo previewVo = createPreview(memberId);

        // 查找收货地址
        List<ReceiverVo> receivers = this.receiverService.findAll(memberId);
        previewVo.setReceivers(receivers);

        previewVo.setBalance(member.getPoints());
        Shopkeeper shopkeeper = this.shopkeeperService.findByMemberId(memberId);
        if (shopkeeper != null) {
            previewVo.setAmountBalance(shopkeeper.getPoints());
        }
        return previewVo;
    }

    private OrderPreviewVo createPreview(Long memberId) {
        OrderPreviewVo previewVo = new OrderPreviewVo();
        // 计算商品项
        List<OrderItemPreviewVo> orderItems = new ArrayList<>();
        List<ShoppingCartItemVo> shoppingCarts = this.shoppingCartService.findByMemberId(memberId, true);
        if (CollectionUtils.isEmpty(shoppingCarts)) {
            //psl throw new BizException(BizCodeFace.createBizCode(ErrorCode.DATE_NULL).message("请先添加商品到购物车并选中"));
        }
        shoppingCarts = shoppingCarts.stream().filter(ShoppingCartItemVo::getIsValid).collect(Collectors.toList());
        previewVo.setOrderItems(shoppingCarts);
        Member member = this.memberService.getById(memberId);
        if (MemberStatus.DISABLED.equals(member.getStatus())) {
            //psl throw new BizException(BizCodeFace.createBizCode(ErrorCode.ACCOUNT_LOCKED));
        }

        return previewVo;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public String createOrder(Long memberId, OrderCreateVo createVo) {
        // 加锁
        String redisKey = String.format("lock:orderCreate:%s", memberId);
        String randomStr = UUID.randomUUID().toString();
        try {
            boolean lock = this.redisService.lock(redisKey, randomStr, 10);
            if (!lock) {
                //psl throw new BizException(BizCodeFace.createBizCode(ErrorCode.FAST_FREQUENCY));
            }
            int useBalance = createVo.getBalance();
            if (useBalance < 0) {
                //psl throw new BizException(BizCodeFace.createBizCode(ErrorCode.DATE_NULL).message("抵扣积分不能小于0"));
            }
            
            Member member = this.memberService.getById(memberId);
            if (useBalance > 0 && useBalance > member.getPoints()) {
                //psl throw new BizException(BizCodeFace.createBizCode(ErrorCode.DATE_NULL).message("积分不足"));
            }
            BigDecimal useAmountBalance = createVo.getAmountBalance();
            if (useAmountBalance.compareTo(BigDecimal.ZERO) < 0) {
                //psl throw new BizException(BizCodeFace.createBizCode(ErrorCode.DATE_NULL).message("抵扣余额不能小于0"));
            }
            Shopkeeper shopkeeper = this.shopkeeperService.findByMemberId(memberId);
            if (useAmountBalance.compareTo(BigDecimal.ZERO) > 0 && (shopkeeper == null || useAmountBalance.compareTo(shopkeeper.getPoints()) > 0)) {
                //psl throw new BizException(BizCodeFace.createBizCode(ErrorCode.DATE_NULL).message("余额不足"));
            }

            Receiver receiver = this.receiverService.getById(createVo.getReceiverId());
            if (receiver == null || !memberId.equals(receiver.getMemberId())) {
                //psl throw new BizException(BizCodeFace.createBizCode(ErrorCode.DATE_NULL).message("收货地址信息不存在"));
            }

            OrderPreviewVo previewVo = createPreview(memberId);

            // 生成订单
            Order order = new Order();
            String orderId = this.redisService.getNextStandardCodeByDayClean(OrderConstant.ORDER_MALL_KEY, 6);
            BigDecimal amount = BigDecimal.ZERO;

            //Long goodsId = 0L;
            //Long goodsSpecId = 0L;
            for (ShoppingCartItemVo orderItem : previewVo.getOrderItems()) {
                if (createVo.getIsGroupon()) {
                    BigDecimal itemAmount = orderItem.getGrouponSubtotalAmount();
                    amount = amount.add(itemAmount);
                    // 保存订单项
                    this.insertOrderItem(memberId, orderId, orderItem.getGoodsSpecsId(), orderItem.getQuantity(), orderItem.getGrouponPrice());
                }else {
                    BigDecimal itemAmount = orderItem.getSubtotalAmount();
                    amount = amount.add(itemAmount);
                    // 保存订单项
                    this.insertOrderItem(memberId, orderId, orderItem.getGoodsSpecsId(), orderItem.getQuantity(), orderItem.getSalePrice());
                }

                //goodsId = orderItem.getGoodsId();
                //goodsSpecId = orderItem.getGoodsSpecsId();
            }
            /*if (createVo.getIsGroupon()) {
                GrouponVo grouponVo = this.grouponService.findByGoodsId(memberId, goodsId);
                Assert.isTrue(!grouponVo.getHasBuy(), "已参加过团购");
            }*/

            OrderSettingsVo settings = this.settingsService.getSettings(OrderSettingsVo.class);
            BigDecimal usePoints = BigDecimal.valueOf(useBalance);
            // 积分抵扣金额的换算比例
            BigDecimal pointsExchangeAmount = Optional.ofNullable(settings.getPointsExchangeAmount()).orElse(new BigDecimal("0.1"));
            BigDecimal pointsDeductAmount = usePoints.multiply(pointsExchangeAmount);
            if (pointsDeductAmount.compareTo(amount) > 0) {
                BigDecimal divide = amount.divide(pointsExchangeAmount, 0, RoundingMode.UP);
                if (pointsDeductAmount.compareTo(divide) > 0) {
                    //psl throw new BizException(BizCodeFace.createBizCode(ErrorCode.FAIL).message("超过最大可使用积分"));
                }
            }
            if (useAmountBalance.compareTo(amount) > 0) {
                //psl throw new BizException(BizCodeFace.createBizCode(ErrorCode.FAIL).message("超过最大可使用余额"));
            }
            // 如果余额+积分>订单金额，优先使用积分，再重新计算余额抵扣
            if (pointsDeductAmount.add(useAmountBalance).compareTo(amount) > 0) {
                useAmountBalance = amount.subtract(pointsDeductAmount);
                if (useAmountBalance.compareTo(BigDecimal.ZERO) < 0) {
                    useAmountBalance = BigDecimal.ZERO;
                }
            }

            if (useBalance > 0) {
                if (createVo.getIsGroupon()) {
                    this.memberPointsService.award(memberId, -useBalance, MemberPointsLogType.GROUPON, orderId);
                }else {
                    this.memberPointsService.award(memberId, -useBalance, MemberPointsLogType.EXCHANGE_GOODS, orderId);
                }
            }
            if (useAmountBalance.compareTo(BigDecimal.ZERO) > 0) {
                if (createVo.getIsGroupon()) {
                    this.shopkeeperPointsLogService.award(shopkeeper.getId(), BigDecimal.ZERO.subtract(useAmountBalance), ShopkeeperPointsLogType.GROUPON, orderId, memberId);
                }else {
                    this.shopkeeperPointsLogService.award(shopkeeper.getId(), BigDecimal.ZERO.subtract(useAmountBalance), ShopkeeperPointsLogType.MALL, orderId, memberId);
                }
            }

            order.setId(orderId);
            order.setMemberId(memberId);
            order.setUsername(member.getPhone());
            order.setAmount(amount);
            order.setUsePoints(usePoints);

            pointsDeductAmount = pointsDeductAmount.compareTo(amount) > 0 ? amount : pointsDeductAmount;
            order.setPointsDeductAmount(pointsDeductAmount);
            order.setWalletDeductAmount(useAmountBalance);
            BigDecimal realAmount = amount.subtract(pointsDeductAmount).subtract(useAmountBalance);
            realAmount = realAmount.compareTo(BigDecimal.ZERO) < 0 ? BigDecimal.ZERO : realAmount;
            order.setRealAmount(realAmount);
            if (!createVo.getIsGroupon()) {
                // 奖励积分根据支付金额折算
                BigDecimal amountExchangePoints = Optional.ofNullable(settings.getAmountExchangePoints()).orElse(BigDecimal.TEN);
                BigDecimal rewardPoints = realAmount.multiply(amountExchangePoints);
                order.setRewardPoints(rewardPoints);
            }else {
                order.setRewardPoints(BigDecimal.ZERO);
            }

            //设置支付过期时间
            Integer payTimeout = settings.getPayTimeout();
            if (payTimeout != null && payTimeout > 0) {
                order.setExpiryTime(LocalDateTime.now().plusHours(payTimeout));
            } else {
                // 默认2个小时有效期
                order.setExpiryTime(LocalDateTime.now().plusHours(2));
            }

            order.setPaymentStatus(PaymentStatus.WAIT);
            order.setUserMemo(createVo.getMemos());
            order.setRegionId(receiver.getRegionId());
            order.setAddress(receiver.getAreaName() + receiver.getAddress());
            order.setConsignee(receiver.getConsignee());
            order.setPhone(receiver.getPhone());
            order.setDeliverStatus(DeliverStatus.WAIT_DELIVER);
            order.setStatus(OrderStatus.WAIT_PAY);
            if (createVo.getIsGroupon()) {
                order.setOrderType(OrderType.GROUPON);
            }else {
                order.setOrderType(OrderType.POINTS);
            }
            // 邀请人不能等于下单人
            if (Objects.equals(createVo.getInviteId(), memberId)) {
                order.setInviteId(0L);
            }else {
                order.setInviteId(createVo.getInviteId());
            }
            boolean saveOrder = this.save(order);
            if (!saveOrder) {
                //psl throw new BizException(BizCodeFace.createBizCode(ErrorCode.FAIL));
            }

            // 记录日志
            OrderLog log = new OrderLog();
            log.setOrderId(orderId);
            if (createVo.getIsGroupon()) {
                log.setOrderType(OrderType.GROUPON);
            }else {
                log.setOrderType(OrderType.POINTS);
            }
            log.setType(OrderLogType.CREATE);
            log.setMemo(member.getPhone() + "创建订单" + orderId);
            this.orderLogMapper.insert(log);
            return orderId;
        }finally {
            boolean unLock = this.redisService.unLock(redisKey, randomStr);
            if (!unLock) {
                this.redisService.unLock(redisKey, randomStr);
            }
        }
        // todo 增加消息通知
        /*String messageBody = String.format("您通过商城兑换%s消耗了%d积分！", goodsName, orderTotalPoints);
        this.messageService.create(memberId, MessageType.POINTS, MessageType.POINTS.getDesc(), messageBody);*/
    }

    @Override
    public String updateOrder(Long memberId, OrderUpdateVo updateVo) {
        // 加锁
        String redisKey = String.format("lock:orderUpdate:%s", memberId);
        String randomStr = UUID.randomUUID().toString();
        try {
            boolean lock = this.redisService.lock(redisKey, randomStr, 10);
            if (!lock) {
                //psl throw new BizException(BizCodeFace.createBizCode(ErrorCode.FAST_FREQUENCY));
            }
            String orderId = updateVo.getOrderId();
            Order order = this.getById(orderId);
            Assert.isTrue(order != null && Objects.equals(order.getMemberId(), memberId), "订单不存在！");
            Assert.isTrue(Objects.equals(order.getStatus(), OrderStatus.WAIT_PAY), "订单已付款成功，请勿重复提交！");
            Assert.isTrue(order.getExpiryTime().isAfter(LocalDateTime.now()), "订单已过期，请重新下单！");
            int useBalance = updateVo.getBalance();
            if (useBalance < 0) {
                //psl throw new BizException(BizCodeFace.createBizCode(ErrorCode.DATE_NULL).message("抵扣积分不能小于0"));
            }

            Member member = this.memberService.getById(memberId);
            if (useBalance > 0 && useBalance > member.getPoints()) {
                //psl throw new BizException(BizCodeFace.createBizCode(ErrorCode.DATE_NULL).message("积分不足"));
            }
            BigDecimal useAmountBalance = updateVo.getAmountBalance();
            if (useAmountBalance.compareTo(BigDecimal.ZERO) < 0) {
                //psl throw new BizException(BizCodeFace.createBizCode(ErrorCode.DATE_NULL).message("抵扣余额不能小于0"));
            }
            Shopkeeper shopkeeper = this.shopkeeperService.findByMemberId(memberId);
            if (useAmountBalance.compareTo(BigDecimal.ZERO) > 0 && (shopkeeper == null || useAmountBalance.compareTo(shopkeeper.getPoints()) > 0)) {
                //psl throw new BizException(BizCodeFace.createBizCode(ErrorCode.DATE_NULL).message("余额不足"));
            }

            Receiver receiver = this.receiverService.getById(updateVo.getReceiverId());
            if (receiver == null || !memberId.equals(receiver.getMemberId())) {
                //psl throw new BizException(BizCodeFace.createBizCode(ErrorCode.DATE_NULL).message("收货地址信息不存在"));
            }

            BigDecimal amount = order.getAmount();

            OrderSettingsVo settings = this.settingsService.getSettings(OrderSettingsVo.class);
            BigDecimal usePoints = BigDecimal.valueOf(useBalance);
            // 积分抵扣金额的换算比例
            BigDecimal pointsExchangeAmount = Optional.ofNullable(settings.getPointsExchangeAmount()).orElse(new BigDecimal("0.1"));
            BigDecimal pointsDeductAmount = usePoints.multiply(pointsExchangeAmount);
            if (pointsDeductAmount.compareTo(amount) > 0) {
                BigDecimal divide = amount.divide(pointsExchangeAmount, 0, RoundingMode.UP);
                if (pointsDeductAmount.compareTo(divide) > 0) {
                    //psl throw new BizException(BizCodeFace.createBizCode(ErrorCode.FAIL).message("超过最大可使用积分"));
                }
            }
            if (useAmountBalance.compareTo(amount) > 0) {
                //psl throw new BizException(BizCodeFace.createBizCode(ErrorCode.FAIL).message("超过最大可使用余额"));
            }
            // 如果余额+积分>订单金额，优先使用积分，再重新计算余额抵扣
            if (pointsDeductAmount.add(useAmountBalance).compareTo(amount) > 0) {
                useAmountBalance = amount.subtract(pointsDeductAmount);
            }
            if (order.getUsePoints().compareTo(BigDecimal.ZERO) > 0) {
                this.memberPointsService.award(memberId, order.getUsePoints().intValue(), MemberPointsLogType.MALL_RETURN, orderId);
            }
            if (useBalance > 0) {
                this.memberPointsService.award(memberId, -useBalance, MemberPointsLogType.EXCHANGE_GOODS, orderId);
            }

            if (order.getWalletDeductAmount().compareTo(BigDecimal.ZERO) > 0) {
                this.shopkeeperPointsLogService.award(shopkeeper.getId(), order.getWalletDeductAmount(), ShopkeeperPointsLogType.MALL_BACK, orderId, memberId);
            }
            if (useAmountBalance.compareTo(BigDecimal.ZERO) > 0) {
                this.shopkeeperPointsLogService.award(shopkeeper.getId(), BigDecimal.ZERO.subtract(useAmountBalance), ShopkeeperPointsLogType.MALL, orderId, memberId);
            }

            order.setUsePoints(usePoints);

            pointsDeductAmount = pointsDeductAmount.compareTo(amount) > 0 ? amount : pointsDeductAmount;
            order.setPointsDeductAmount(pointsDeductAmount);
            order.setWalletDeductAmount(useAmountBalance);
            BigDecimal realAmount = amount.subtract(pointsDeductAmount).subtract(useAmountBalance);
            realAmount = realAmount.compareTo(BigDecimal.ZERO) < 0 ? BigDecimal.ZERO : realAmount;
            order.setRealAmount(realAmount);
            if (Objects.equals(order.getOrderType(), OrderType.POINTS)) {
                // 奖励积分根据支付金额折算
                BigDecimal amountExchangePoints = Optional.ofNullable(settings.getAmountExchangePoints()).orElse(BigDecimal.TEN);
                BigDecimal rewardPoints = realAmount.multiply(amountExchangePoints);
                order.setRewardPoints(rewardPoints);
            }else {
                order.setRewardPoints(BigDecimal.ZERO);
            }

            //设置支付过期时间
            Integer payTimeout = settings.getPayTimeout();
            if (payTimeout != null && payTimeout > 0) {
                order.setExpiryTime(LocalDateTime.now().plusHours(payTimeout));
            } else {
                // 默认2个小时有效期
                order.setExpiryTime(LocalDateTime.now().plusHours(2));
            }

            order.setPaymentStatus(PaymentStatus.WAIT);
            order.setUserMemo(updateVo.getMemos());
            order.setRegionId(receiver.getRegionId());
            order.setAddress(receiver.getAreaName() + receiver.getAddress());
            order.setConsignee(receiver.getConsignee());
            order.setPhone(receiver.getPhone());
            order.setDeliverStatus(DeliverStatus.WAIT_DELIVER);
            order.setStatus(OrderStatus.WAIT_PAY);

            boolean saveOrder = this.updateById(order);
            if (!saveOrder) {
                //psl throw new BizException(BizCodeFace.createBizCode(ErrorCode.FAIL));
            }

            // 记录日志
            OrderLog log = new OrderLog();
            log.setOrderId(orderId);
            log.setOrderType(order.getOrderType());
            log.setType(OrderLogType.MODIFY);
            log.setMemo(member.getPhone() + "修改订单" + orderId);
            this.orderLogMapper.insert(log);
            return orderId;
        }finally {
            boolean unLock = this.redisService.unLock(redisKey, randomStr);
            if (!unLock) {
                this.redisService.unLock(redisKey, randomStr);
            }
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void payment(Payment payment) {
        logger.info("开始处理注册订单支付回调，流水号[{}]", payment.getId());
        String orderId = payment.getOrderId();
        Order order = this.getById(orderId);
        order.setTradeNo(payment.getId());
        order.setExpiryTime(null);
        order.setDeliverStatus(DeliverStatus.WAIT_DELIVER);
        order.setStatus(OrderStatus.WAIT_DELIVER);
        order.setPaymentStatus(PaymentStatus.SUCCESS);
        order.setPaymentMethod(payment.getPaymentMethod());
        order.setPaymentTime(LocalDateTime.now());
        this.updateById(order);

        // 记录支付订单日志
        OrderLog orderLog = new OrderLog();
        orderLog.setOrderId(order.getId());
        orderLog.setOrderType(order.getOrderType());
        orderLog.setType(OrderLogType.PAYMENT);
        orderLog.setMemo("订单支付成功");
        this.orderLogMapper.insert(orderLog);

        if (Objects.equals(OrderType.GROUPON, order.getOrderType())) {
            List<OrderItem> orderItems = this.orderItemService.findByOrderId(orderId);
            Long goodsId = 0L;
            Long goodsSpecId = 0L;
            for (OrderItem orderItem : orderItems) {
                goodsId = orderItem.getGoodsId();
                goodsSpecId = orderItem.getGoodsSpecId();
            }
            // 支付成功插入团购记录
            GrouponCreateVo grouponCreateVo = new GrouponCreateVo();
            grouponCreateVo.setOrderId(orderId);
            grouponCreateVo.setGoodsId(goodsId);
            grouponCreateVo.setGoodsSpecId(goodsSpecId);
            grouponCreateVo.setMemberId(order.getMemberId());
            grouponCreateVo.setInviteId(order.getInviteId());
            this.grouponService.createLog(grouponCreateVo);
        }
    }

    @Override
    public PageVo<OrderListVo> list(Long memberId, AppOrderCommonQueryParam queryParam) {
        Page<Order> page = new Page<>(queryParam.getCurrent(), queryParam.getPageSize());
        page.setOrders(Lists.newArrayList(com.baomidou.mybatisplus.core.metadata.OrderItem.desc("create_time")));
        QueryWrapper<Order> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(Order::getMemberId, memberId);
        queryWrapper.lambda().in(Order::getOrderType, Lists.newArrayList(OrderType.POINTS, OrderType.GROUPON));
        if (queryParam.getStatus() != null) {
            queryWrapper.lambda().eq(Order::getStatus, queryParam.getStatus());
        }
        if (queryParam.getDeliverStatus() != null) {
            queryWrapper.lambda().eq(Order::getDeliverStatus, queryParam.getDeliverStatus());
        }
        if (queryParam.getCommentStatus() != null) {
            queryWrapper.lambda().eq(Order::getCommentStatus, queryParam.getCommentStatus());
        }
        Page<Order> orderPage = this.page(page, queryWrapper);
        if (CollectionUtils.isEmpty(orderPage.getRecords())) {
            return PageVo.create(queryParam.getCurrent(), queryParam.getPageSize(), 0, Lists.newArrayList());
        }
        List<String> orderIds = orderPage.getRecords().stream().map(Order::getId).collect(Collectors.toList());
        List<GrouponLog> grouponLogs = this.grouponService.findByOrderId(memberId, orderIds);
        Map<String, GrouponLog> grouponLogMap = new HashMap<>();
        if (!CollectionUtils.isEmpty(grouponLogs)) {
            grouponLogMap = grouponLogs.stream().collect(Collectors.toMap(GrouponLog::getOrderId, log -> log));
        }

        Map<String, GrouponLog> finalGrouponLogMap = grouponLogMap;
        List<OrderListVo> resultList = orderPage.getRecords().stream().map(item -> {
            OrderListVo orderListVo = OrderConvert.INSTANCE.entity2Vo(item);
            if (Objects.equals(item.getOrderType(), OrderType.POINTS) && item.getRealAmount() != null) {
                BigDecimal divide = item.getRealAmount().divide(BigDecimal.TEN, 0, RoundingMode.FLOOR);
                orderListVo.setRewardPoints(divide);
            }else {
                orderListVo.setRewardPoints(null);
            }
            List<OrderItem> orderItems = this.orderItemService.findByOrderId(item.getId());
            List<OrderItemVo> orderItemVos = new ArrayList<>();
            for (OrderItem orderItem : orderItems) {
                OrderItemVo itemVo = convertOrderItem(orderItem);
                orderItemVos.add(itemVo);
            }
            orderListVo.setItems(orderItemVos);

            // 团购信息
            GrouponLog grouponLog = finalGrouponLogMap.get(item.getId());
            if (grouponLog != null) {
                orderListVo.setGrouponPrice(grouponLog.getGrouponPrice());
                orderListVo.setGrouponStatus(grouponLog.getStatus());
            }
            return orderListVo;
        }).collect(Collectors.toList());

        return PageVo.create(queryParam.getCurrent(), queryParam.getPageSize(), orderPage.getTotal(), resultList);
    }

    @Override
    public PageVo<OrderCommentListVo> commentList(Long memberId, PageParams queryParam) {
        Page<Order> page = new Page<>(queryParam.getCurrent(), queryParam.getPageSize());
        QueryWrapper<Order> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(Order::getMemberId, memberId);
        queryWrapper.lambda().eq(Order::getStatus, OrderStatus.FINISHED);
        queryWrapper.lambda().eq(Order::getCommentStatus, CommentStatus.COMMENT);
        Page<Order> orderPage = this.getBaseMapper().selectPage(page, queryWrapper);
        List<Order> records = orderPage.getRecords();
        if (CollectionUtils.isEmpty(records)) {
            return PageVo.create(queryParam.getCurrent(), queryParam.getPageSize(), 0, Lists.newArrayList());
        }

        List<OrderCommentListVo> list = records.stream().map(item -> {
            OrderCommentListVo vo = new OrderCommentListVo();
            vo.setId(item.getId());
            vo.setStatus(item.getStatus());
            vo.setUserPoints(item.getUsePoints());
            OrderComment orderComment = this.orderCommentService.findByOrderId(item.getId());
            vo.setServiceScore(orderComment.getServiceScore());
            vo.setShippingScore(orderComment.getShippingScore());
            vo.setPackageScore(orderComment.getPackageScore());

            List<GoodsComment> goodsComments = this.goodsCommentMapper.selectList(Wrappers.<GoodsComment>lambdaQuery()
                    .eq(GoodsComment::getCommentId, orderComment.getId()));
            Map<Long, List<GoodsComment>> goodsCommentMap = goodsComments.stream().collect(Collectors.groupingBy(GoodsComment::getGoodsSpecsId));
            List<OrderItem> orderItems = this.orderItemService.findByOrderId(item.getId());
            List<OrderItemCommentVo> orderItemVos = new ArrayList<>();
            for (OrderItem orderItem : orderItems) {
                OrderItemCommentVo itemVo = new OrderItemCommentVo();
                itemVo.setId(orderItem.getId());
                itemVo.setGoodsId(orderItem.getGoodsId());
                itemVo.setGoodsName(orderItem.getGoodsName());
                itemVo.setSpu(orderItem.getSpu());
                itemVo.setGoodsSpecId(orderItem.getGoodsSpecId());
                itemVo.setGoodsSpec(orderItem.getGoodsSpec());
                itemVo.setSku(orderItem.getSku());
                if (!StringUtils.hasText(orderItem.getPicture())) {
                    Long goodsId = orderItem.getGoodsId();
                    Goods goods = this.goodsMapper.selectById(goodsId);
                    if (goods != null) {
                        itemVo.setPicture(goods.getPicture());
                    }
                }else {
                    itemVo.setPicture(orderItem.getPicture());
                }
                itemVo.setPrice(orderItem.getPrice());
                itemVo.setQuantity(orderItem.getQuantity());
                itemVo.setExchangePoints(orderItem.getExchangePoints().intValue());

                List<GoodsComment> comments = goodsCommentMap.get(orderItem.getGoodsSpecId());
                if (!CollectionUtils.isEmpty(comments)) {
                    GoodsComment goodsComment = comments.get(0);
                    itemVo.setIsAnonymous(goodsComment.getIsAnonymous());
                    itemVo.setContent(goodsComment.getContent());
                    itemVo.setPictures(goodsComment.getPictures());
                    itemVo.setScore(goodsComment.getScore());
                }
                orderItemVos.add(itemVo);
            }
            vo.setItems(orderItemVos);
            return vo;
        }).collect(Collectors.toList());
        return PageVo.create(queryParam.getCurrent(), queryParam.getPageSize(), orderPage.getTotal(), list);
    }

    @Override
    public OrderDetailVo detail(Long memberId, String orderId) {
        OrderDetailVo detailVo = new OrderDetailVo();
        Order order = this.getById(orderId);
        Assert.notNull(order, "未找到订单信息");
        if (!memberId.equals(order.getMemberId())) {
            return detailVo;
        }
        detailVo = OrderConvert.INSTANCE.entity2DetailVo(order);
        if (Objects.equals(detailVo.getOrderType(), OrderType.POINTS)) {
            BigDecimal divide = detailVo.getRealAmount().divide(BigDecimal.TEN, 0, RoundingMode.FLOOR);
            detailVo.setRewardPoints(divide);
        }else {
            detailVo.setRewardPoints(null);
        }
        List<OrderItem> orderItems = this.orderItemService.findByOrderId(orderId);
        List<OrderItemVo> orderItemVos = new ArrayList<>();
        for (OrderItem orderItem : orderItems) {
            OrderItemVo itemVo = convertOrderItem(orderItem);
            // 查询退款退货状态
            OrderReturn orderReturn = this.orderReturnMapper.selectOne(new QueryWrapper<OrderReturn>().lambda()
                    .eq(OrderReturn::getOrderItemId, orderItem.getId())
                    .orderByDesc(OrderReturn::getCreateTime)
                    .last("limit 1"));
            if (orderReturn != null) {
                itemVo.setOrderReturnId(orderReturn.getId());
                itemVo.setAuditStatus(orderReturn.getAuditStatus());
                itemVo.setReturnType(orderReturn.getReturnType());
            }

            if (!StringUtils.hasText(itemVo.getPicture())) {
                Long goodsId = orderItem.getGoodsId();
                Goods goods = this.goodsMapper.selectById(goodsId);
                if (goods != null) {
                    itemVo.setPicture(goods.getPicture());
                }
            }
            orderItemVos.add(itemVo);
        }
        detailVo.setItems(orderItemVos);

        QueryTrackResp queryTrackResp = this.deliveryService.queryTrack(order.getLogisticsCompany(), order.getLogisticsNo(), order.getPhone());
        if (queryTrackResp != null && !CollectionUtils.isEmpty(queryTrackResp.getData())) {
            detailVo.setLastLogisticsInfo(queryTrackResp.getData().get(0).getContext());
            detailVo.setLastLogisticsTime(queryTrackResp.getData().get(0).getTime());
        }

        return detailVo;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public OrderPreviewVo rebuild(Long memberId, String orderId) {
        OrderDetailVo detailVo = this.detail(memberId, orderId);
        Assert.notNull(detailVo, "未找到订单信息");
        //取消所有商品选择
        this.shoppingCartService.changeAllSelect(memberId, false);
        List<OrderItemVo> orderItems = detailVo.getItems();
        // 添加到购物车
        for (OrderItemVo itemVo : orderItems) {
            boolean result = this.shoppingCartService.addToCart(memberId, itemVo.getGoodsSpecId(), itemVo.getQuantity());
            if (!result) {
                //psl throw new BizException(BizCodeFace.createBizCode(ErrorCode.FAIL));
            }
        }
        return this.preview(memberId);
    }

    @Override
    public OrderPreviewVo directBuy(Long memberId, Long goodsSpecsId, Integer quantity, Boolean isGroupon) {
        //取消所有商品选择
        this.shoppingCartService.changeAllSelect(memberId, false);
        // 添加到购物车
        boolean result = this.shoppingCartService.addToCart(memberId, goodsSpecsId, quantity);
        result = result && this.shoppingCartService.changeQuantity(memberId, goodsSpecsId, 1);
        if (!result) {
            //psl throw new BizException(BizCodeFace.createBizCode(ErrorCode.FAIL).message("购物车异常"));
        }
        OrderPreviewVo previewVo = this.preview(memberId);
        previewVo.setIsGroupon(isGroupon);
        return previewVo;
    }

    private OrderItemVo convertOrderItem(OrderItem orderItem) {
        OrderItemVo itemVo = OrderConvert.INSTANCE.entity2Vo(orderItem);
        // 查询退款退货状态
        OrderReturn orderReturn = this.orderReturnMapper.selectOne(new QueryWrapper<OrderReturn>().lambda()
                .eq(OrderReturn::getOrderItemId, orderItem.getId())
                .orderByDesc(OrderReturn::getCreateTime)
                .last("limit 1"));
        if (orderReturn != null) {
            itemVo.setAuditStatus(orderReturn.getAuditStatus());
            itemVo.setReturnType(orderReturn.getReturnType());
        }

        if (!StringUtils.hasText(itemVo.getPicture())) {
            Long goodsId = orderItem.getGoodsId();
            Goods goods = this.goodsMapper.selectById(goodsId);
            if (goods != null) {
                itemVo.setPicture(goods.getPicture());
            }
        }
        return itemVo;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void comment(Long memberId, OrderCommentCreateVo createVo, HttpServletRequest request) {
        Order order = this.getById(createVo.getOrderId());
        Assert.isTrue(order != null && order.getMemberId().equals(memberId), "未找到订单");
        Assert.isTrue(CommentStatus.WAIT_COMMENT.equals(order.getCommentStatus()) && DeliverStatus.RECEIVED.equals(order.getDeliverStatus()), "订单状态异常");

        order.setCommentStatus(CommentStatus.COMMENT);
        order.setCommentTime(LocalDateTime.now());
        boolean updateOrder = this.updateById(order);
        if (!updateOrder) {
            //psl throw new BizException(BizCodeFace.createBizCode(ErrorCode.FAIL));
        }

        // 判断订单是否已评价
        OrderComment existOrderComment = this.orderCommentService.findByOrderId(createVo.getOrderId());
        Assert.isTrue(existOrderComment == null, "订单已评价");

        String ip = IpUtil.getIpAddress(request);

        OrderComment orderComment = new OrderComment();
        BeanUtils.copyProperties(createVo, orderComment);
        orderComment.setMemberId(memberId);
        boolean result = this.orderCommentService.save(orderComment);
        if (!result) {
            //psl throw new BizException(BizCodeFace.createBizCode(ErrorCode.FAIL));
        }

        Member member = this.memberService.getById(memberId);
        for (GoodsCommentCreateVo commentCreateVo : createVo.getItem()) {
            GoodsComment goodsComment = new GoodsComment();
            BeanUtils.copyProperties(commentCreateVo, goodsComment);
            goodsComment.setCommentId(orderComment.getId());
            goodsComment.setMemberId(memberId);
            GoodsSpecs goodsSpecs = this.goodsSpecsMapper.selectById(commentCreateVo.getGoodsSpecsId());
            if (goodsSpecs == null) {
                continue;
            }
            Goods goods = this.goodsMapper.selectById(goodsSpecs.getGoodsId());
            if (goods == null) {
                continue;
            }
            goodsComment.setGoodsId(goods.getId());
            goodsComment.setNickname(member.getNickname());
            goodsComment.setAvatar(member.getAvatar());
            goodsComment.setIp(ip);
            goodsComment.setIsAnonymous(createVo.getIsAnonymous());
            goodsComment.setIsShow(false);
            goodsComment.setGoodsType(GoodsType.POINTS_GOODS);
            int goodsCommentResult = this.goodsCommentMapper.insert(goodsComment);
            if (goodsCommentResult < 1) {
                //psl throw new BizException(BizCodeFace.createBizCode(ErrorCode.FAIL));
            }
        }

        // 记录日志
        OrderLog orderLog = new OrderLog();
        orderLog.setOrderId(createVo.getOrderId());
        orderLog.setOrderType(order.getOrderType());
        orderLog.setType(OrderLogType.COMMENT);
        orderLog.setMemo("订单评价");
        int insert = this.orderLogMapper.insert(orderLog);
        if (insert < 1) {
            //psl throw new BizException(BizCodeFace.createBizCode(ErrorCode.FAIL));
        }
    }

    /**
     * 保存订单项
     * @param memberId 用户id
     * @param orderId 订单id
     * @param goodsSpecsId 商品规格id
     * @param quantity 数量
     */
    private void insertOrderItem(Long memberId, String orderId, Long goodsSpecsId, Integer quantity, BigDecimal price) {
        // 校验商品状态
        GoodsSpecs goodsSpecs = this.goodsSpecsMapper.selectById(goodsSpecsId);
        // 增加销量锁定库存
        goodsSpecs.setStock(goodsSpecs.getStock() - quantity);
        goodsSpecs.setSales(goodsSpecs.getSales() + quantity);
        goodsSpecs.setVersion(goodsSpecs.getVersion());
        int updateGoodsSpecs = this.goodsSpecsMapper.updateById(goodsSpecs);
        if (updateGoodsSpecs < 1) {
            //psl throw new BizException(BizCodeFace.createBizCode(ErrorCode.FAIL));
        }
        Goods goods = this.goodsMapper.selectById(goodsSpecs.getGoodsId());
        goods.setSales(goods.getSales() + quantity);
        this.goodsMapper.updateById(goods);

        OrderItem orderItem = new OrderItem();
        orderItem.setOrderId(orderId);
        orderItem.setGoodsId(goods.getId());
        orderItem.setGoodsName(goods.getName());
        orderItem.setSpu(goods.getSpu());
        orderItem.setGoodsSpecId(goodsSpecs.getId());
        orderItem.setGoodsSpec(goodsSpecs.getGoodsSpec());
        orderItem.setSku(goodsSpecs.getSku());
        orderItem.setPicture(goodsSpecs.getPicture());
        orderItem.setCostPrice(goodsSpecs.getCostPrice());
        orderItem.setFreight(goods.getFreight());
        orderItem.setPrice(price);
        orderItem.setExchangePoints(new BigDecimal(goodsSpecs.getExchangePoints()));
        orderItem.setQuantity(quantity);
        boolean saveOrderItem = this.orderItemService.save(orderItem);
        if (!saveOrderItem) {
            //psl throw new BizException(BizCodeFace.createBizCode(ErrorCode.FAIL));
        }

        // 从购物车移除
        this.shoppingCartService.remove(new QueryWrapper<ShoppingCart>().lambda()
                .eq(ShoppingCart::getMemberId, memberId)
                .eq(ShoppingCart::getGoodsSpecsId, goodsSpecsId));
    }

    @Autowired
    public void setReceiverService(ReceiverService receiverService) {
        this.receiverService = receiverService;
    }

    @Autowired
    public void setRedisService(IRedisService redisService) {
        this.redisService = redisService;
    }

    @Autowired
    public void setSettingsService(ISettingsService settingsService) {
        this.settingsService = settingsService;
    }

    @Autowired
    public void setGoodsSpecsMapper(GoodsSpecsMapper goodsSpecsMapper) {
        this.goodsSpecsMapper = goodsSpecsMapper;
    }

    @Autowired
    public void setGoodsMapper(GoodsMapper goodsMapper) {
        this.goodsMapper = goodsMapper;
    }

    @Autowired
    public void setOrderItemService(IOrderItemService orderItemService) {
        this.orderItemService = orderItemService;
    }

    @Autowired
    public void setMemberService(AppMemberService memberService) {
        this.memberService = memberService;
    }

    @Autowired
    public void setOrderLogMapper(OrderLogMapper orderLogMapper) {
        this.orderLogMapper = orderLogMapper;
    }

    @Autowired
    public void setOrderCommentService(IOrderCommentService orderCommentService) {
        this.orderCommentService = orderCommentService;
    }

    @Autowired
    public void setGoodsCommentMapper(GoodsCommentMapper goodsCommentMapper) {
        this.goodsCommentMapper = goodsCommentMapper;
    }

    @Autowired
    public void setDeliveryService(IDeliveryService deliveryService) {
        this.deliveryService = deliveryService;
    }

    @Autowired
    public void setOrderReturnMapper(OrderReturnMapper orderReturnMapper) {
        this.orderReturnMapper = orderReturnMapper;
    }

    @Autowired
    public void setMemberPointsService(MemberPointsService memberPointsService) {
        this.memberPointsService = memberPointsService;
    }

    @Autowired
    public void setMessageService(MessageService messageService) {
        this.messageService = messageService;
    }

    @Autowired
    public void setShoppingCartService(ShoppingCartService shoppingCartService) {
        this.shoppingCartService = shoppingCartService;
    }

    @Autowired
    public void setShopkeeperService(ShopkeeperService shopkeeperService) {
        this.shopkeeperService = shopkeeperService;
    }

    @Autowired
    public void setShopkeeperPointsLogService(ShopkeeperPointsLogService shopkeeperPointsLogService) {
        this.shopkeeperPointsLogService = shopkeeperPointsLogService;
    }

    @Autowired
    public void setGrouponService(AppGrouponService grouponService) {
        this.grouponService = grouponService;
    }
}
